package com.nineclock.approve.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.support.hsf.HSFJSONUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nineclock.approve.dto.*;
import com.nineclock.approve.mapper.ApproveDefinitionMapper;
import com.nineclock.approve.pojo.ApproveDefinition;
import com.nineclock.approve.service.ActivitiService;
import com.nineclock.approve.service.ApproveDefinitionService;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.JsonUtils;
import com.nineclock.common.utils.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import springfox.documentation.spring.web.json.Json;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
@Transactional
public class ApproveDefinitionServiceImpl implements ApproveDefinitionService {
    @Autowired
    ApproveDefinitionMapper approveDefinitionMapper;

    @Override
    public List<ApproveGroupDefinitionDto> queryApproveGroupDefinition (){
        List<ApproveGroupDefinitionDto> approveGroupDefinitionDtos=new ArrayList<ApproveGroupDefinitionDto>();

        //查询当前企业关联的流程定义
        LambdaQueryWrapper<ApproveDefinition> definitionWq=new LambdaQueryWrapper<>();

        definitionWq.eq(ApproveDefinition::getCompanyId,CurrentUserHolder.get().getCompanyId());
        definitionWq.eq(ApproveDefinition::getIsValid,1);

        List<ApproveDefinition> approveDefinitions=approveDefinitionMapper.selectList(definitionWq);

        //组装数据
        if(CollectionUtil.isNotEmpty(approveDefinitions)) {
            Map<String,List<ApproveDefinition>> map=approveDefinitions.stream().collect(Collectors.groupingBy(ApproveDefinition::getGroupType));

            for(String groupType : map.keySet()) {
                ApproveGroupDefinitionDto approveGroupDefinitionDto=new ApproveGroupDefinitionDto();
                approveGroupDefinitionDto.setGroupType(groupType);
                approveGroupDefinitionDto.setDefinitionList(map.get(groupType));
                System.out.println(approveGroupDefinitionDtos);
                approveGroupDefinitionDtos.add(approveGroupDefinitionDto);
            }
        }
        return approveGroupDefinitionDtos;
    }

    @Autowired
    ActivitiService activitiService;
    /**
     * 新增 & 修改
     * @param approveDefinitionSaveDto
     */
    @Override
    public void saveAndModifyQuote (ApproveDefinitionSaveDto approveDefinitionSaveDto){

        ////基础信息
        ApproveDefinitionBaseDataDto baseData=approveDefinitionSaveDto.getBaseData();
        //流程信息
        String flowData=approveDefinitionSaveDto.getFlowData();
        //表单信息
        List<ApproveDefinitionTableDataDto> tableData=approveDefinitionSaveDto.getTableData();
        if(baseData==null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        ApproveDefinition definition=null;
        //根据id是否存在判断修改OR 新增
        if(baseData.getId()==null) {
            //新增
            definition=BeanHelper.copyProperties(baseData,ApproveDefinition.class,"allowUserJson");
            definition.setIsValid("1");
            definition.setDataFrom("1");//手动添加
            definition.setCompanyId(CurrentUserHolder.get().getCompanyId()+"");
            //组装流程定义允许操作用户信息
            List<AllowUserObjDto> allowUserJson=baseData.getAllowUserJson();//谁可以发起这个审批json
            definition.setAllowUserJson(JsonUtils.toString(allowUserJson));

            // 组装流程定义的流程信息 ---> 后续拓展使用
            JSONArray jsonArray=JSONUtil.parseArray(flowData);
            expandParamWithNodeKey(jsonArray);
            definition.setFlowJson(JSONUtil.toJsonStr(jsonArray));//组装流程信息

            definition.setFormJson(JsonUtils.toString(tableData));//表单信息
            //对当前流程配置一个统一的名字 tablename ---> 后续拓展使用
            definition.setTableName("flow_"+UUIDUtils.getUUID());
            //需要将所有的表单信息，记录下来并且拓展参数，fieldKey
            definition.setColumns(JsonUtils.toString(expandFieldKey(approveDefinitionSaveDto)));
            approveDefinitionMapper.insert(definition);
            //部署到 Activiti引擎中
            activitiService.deployProcessToActiviti(definition);
        }else {
            //修改
             definition=approveDefinitionMapper.selectById(baseData.getId());
            BeanUtils.copyProperties(baseData,definition);
            definition.setAllowUserJson(JsonUtils.toString(baseData.getAllowUserJson()));
            definition.setFormJson(JsonUtils.toString(approveDefinitionSaveDto.getTableData()));

            definition.setFormJson(JsonUtils.toString( expandFieldKey(approveDefinitionSaveDto)));
            JSONArray jsonArray = JSONUtil.parseArray(approveDefinitionSaveDto.getFlowData());
            expandParamWithNodeKey(jsonArray);
            definition.setFlowJson(JSONUtil.toJsonStr(jsonArray));

            approveDefinitionMapper.updateById(definition);

            activitiService.dropProcessFromActiviti(definition);
            activitiService.deployProcessToActiviti(definition);
        }
    }

    /**
     * 流程定义: 根据ID查询
     * @param id
     * @return
     */
    @Override
    public ApproveDefinitionResultDto queryById (String id){
        if(id==null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        ApproveDefinitionResultDto approveDefinition=new ApproveDefinitionResultDto();
        ApproveDefinition definition=approveDefinitionMapper.selectById(id);
        ApproveDefinitionBaseDataDto definitionBaseDataDto=BeanHelper.copyProperties(definition,ApproveDefinitionBaseDataDto.class);

        List<AllowUserObjDto> allowUserObjDtos=JsonUtils.toList(definition.getAllowUserJson(),AllowUserObjDto.class);
        definitionBaseDataDto.setAllowUserJson(allowUserObjDtos);

        String formJson=definition.getFormJson();
        List<ApproveDefinitionTableDataResultDto> tableList=null;
        if(StrUtil.isNotEmpty(formJson)) {
             tableList=JsonUtils.toList(formJson,ApproveDefinitionTableDataResultDto.class);

        }
        String flowJson=definition.getFlowJson();
        approveDefinition.setBaseData(definitionBaseDataDto)
                .setFlowData(flowJson)
                .setTableData(tableList);


        return approveDefinition;
    }

    /**
     * 扩充参数 : fieldKey
     * @param approveDefinitionDto
     * @return
     */
    private List<ColumnObjDto> expandFieldKey(ApproveDefinitionSaveDto approveDefinitionDto) {
        List<ColumnObjDto> columns = new ArrayList<>();

        for (ApproveDefinitionTableDataDto tableData : approveDefinitionDto.getTableData()) {
            if(StrUtil.isEmpty(tableData.getFieldKey())){
                tableData.setFieldKey(UUIDUtils.getUUID());
            }

            columns.add(new ColumnObjDto(tableData.getFieldKey(), tableData.getLab(), tableData.getTitle(), "1"));
        }
        return columns;
    }
    private void expandParamWithNodeKey(JSONArray jsonArray) {
        for(int i = 0; i < jsonArray.size(); i++){
            JSONObject jsonNode = (JSONObject) jsonArray.get(i);

            String nodeKey = jsonNode.getStr("nodeKey");
            if(StrUtil.isEmpty(nodeKey)){
                jsonNode.put("nodeKey", UUIDUtils.getUUID());
            }

            //处理网关节点的内部节点 nodeKey
            String type = jsonNode.getStr("type");
            if("condition".equals(type)){

                JSONArray batchArray = (JSONArray) jsonNode.get("node");
                if(batchArray!=null && batchArray.size()>0){

                    for (int j = 0; j < batchArray.size(); j++) {
                        JSONArray innerArray = (JSONArray) batchArray.get(j);

                        if(innerArray!=null && innerArray.size()>0){
                            for (int k = 0; k < innerArray.size(); k++) {
                                JSONObject node = (JSONObject) innerArray.get(k);
                                if(!node.containsKey("nodeKey")){
                                    node.put("nodeKey", UUIDUtils.getUUID());
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
